/**
 *
 */
package org.tangdao.common.suports;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

import org.tangdao.common.collect.ListUtils;
import org.tangdao.common.collect.SetUtils;
import org.tangdao.common.exception.ServiceException;
import org.tangdao.common.lang.ObjectUtils;
import org.tangdao.common.lang.StringUtils;
import org.tangdao.common.utils.IdGen;
import org.tangdao.modules.sys.model.domain.Role;
import org.tangdao.modules.sys.model.domain.User;
import org.tangdao.modules.sys.utils.UserUtils;

/**
 * 数据范围查询对象
 * 
 * @author Ryan Ru(ruyangit@gmail.com)
 */
public class DataScopeSqlMap extends LinkedHashMap<String, Object> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

//	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
//	private static final DataScopeSqlMap dataScopeSqlMap = new DataScopeSqlMap();

//	private BaseEntity<?> entity;
//
//	public DataScopeQuery(BaseEntity<?> entity) {
//		this.entity = entity;
//	}
	
//	/**
//	 * 获取当前对象实例
//	 */
//	public static DataScopeSqlMap getInstance() {
//		return dataScopeSqlMap;
//	}
	
	private final Object add(String key, Object value) {
		return this.put(key, value);
	}
	
	/**
	 * 添加到数据范围过滤条件（如果之前sqlMapKey已经存在，则使用OR增加到该条件）
	 * 
	 * @param sqlMapKey sqlMap的键值，举例：如设置“dsf”数据范围过滤，则：exists方式对应：sqlMap.dsf
	 * @param sqlWhere  具体的Where子句。
	 */
	public DataScopeSqlMap addFilter(String sqlMapKey, String sqlWhere) {
//		SqlMap sqlMap = this.entity.getSqlMap();
		String sqlWhereOnce = ObjectUtils.toString2(this.get(sqlMapKey));
		if (StringUtils.isNotBlank(sqlWhereOnce)) {
			this.add(sqlMapKey, " AND ((" + this.removeTheStartingAndOr(sqlWhereOnce) + ") OR ("
					+ this.removeTheStartingAndOr(sqlWhere) + "))");
			return this;
		}
		this.add(sqlMapKey, " AND " + sqlWhere);
//		logger.debug(sqlMapKey, sqlWhere);
		return this;
	}

	/**
	 * 清理数据范围过滤条件
	 * 
	 * @param sqlMapKey 要清理的数据过滤条件
	 */
	public DataScopeSqlMap clearFilter(String sqlMapKey) {
		this.remove(sqlMapKey);
		this.remove(sqlMapKey + "From");
		this.remove(sqlMapKey + "Where");
		return this;
	}

	/**
	 * 
	 * @param sql
	 * @return
	 */
	private String removeTheStartingAndOr(String sql) {
		if (StringUtils.startsWithIgnoreCase(sql = StringUtils.trim(sql), "AND ")) {
			sql = sql.substring("AND ".length());
		}
		if (StringUtils.startsWithIgnoreCase(sql, "OR ")) {
			sql = sql.substring("OR ".length());
		}
		return sql;
	}

	/**
	 * 
	 * @param sqlMapKey
	 * @param sqlFrom
	 * @return
	 */
	private DataScopeSqlMap addJoinFrom(String sqlMapKey, String sqlFrom) {
		String sqlFromOnce = ObjectUtils.toString2(this.get(sqlMapKey + "From"));
		if (StringUtils.isNotBlank(sqlFromOnce)) {
			this.add(sqlMapKey + "From", sqlFromOnce + " " + sqlFrom);
		}
		this.add(sqlMapKey + "From", sqlFrom);
//		logger.debug(sqlMapKey + "From", this.get(sqlMapKey + "From"));
		return this;
	}

	/**
	 * 
	 * @param sqlMapKey
	 * @param sqlWhere
	 * @return
	 */
	private DataScopeSqlMap addJoinWhere(String sqlMapKey, String sqlWhere) {
		return this.addFilter(sqlMapKey + "Where", sqlWhere);
	}

	/**
	 * 
	 * @param sqlMapKey         dsf
	 * @param ctrlTypes         Office,Company
	 * @param bizCtrlDataFields 业务表对应过滤表别名和加权字段，多个使用“,”分隔 部门 a.office_code，公司
	 *                          a.company_code
	 * @param bizCtrlUserField  业务表对应过滤表别名和用户字段，用于过滤只可以查看本人数据 业务表 a.create_by
	 * @param ctrlPermi         拥有的数据权限：DataScope.CTRL_PERMI_HAVE、可管理的数据权限：DataScope.CTRL_PERMI_HAVE
	 * @param bizScope          业务范围
	 * @return
	 */
	public DataScopeSqlMap addFilter(String sqlMapKey, String ctrlTypes, String bizCtrlDataFields,
			String bizCtrlUserField, String ctrlPermi) {
		User user = UserUtils.getUser();
		if (user.isAdmin()) {
			return this;
		}
		List<String> roleCodes = ListUtils.newArrayList();
		Set<String> dataScopes = SetUtils.newHashSet();
		List<Role> roles = user.getRoles();
		for (Role role : roles) {
			if (Role.DATA_SCOPE_NONE.equals(role.getDataScope())) {
				continue;
			}
			if (Role.DATA_SCOPE_ALL.equals(role.getDataScope())) {
				return this;
			}
			if (Role.DATA_SCOPE_CUSTOM.equals(role.getDataScope())) {
				roleCodes.add(role.getRoleCode());
				continue;
			}
			dataScopes.add(role.getDataScope());
		}
		String[] ctrlTypeArray = StringUtils.split(ctrlTypes, ",");
		String[] bizCtrlDataFieldArray = StringUtils.split(bizCtrlDataFields, ",");
		if (ctrlTypeArray == null || bizCtrlDataFieldArray == null
				|| ctrlTypeArray.length != bizCtrlDataFieldArray.length) {
			throw new ServiceException("参数匹配异常");
		}
		for (int i = 0; i < ctrlTypeArray.length; i++) {
			if ("Role".equals(ctrlTypeArray[i])) {
				this.addRoleDataScope(sqlMapKey, user, bizCtrlDataFieldArray[i]);
			} else {
				this.addUserDataScope(sqlMapKey, user, ctrlTypeArray[i], ctrlPermi, bizCtrlDataFieldArray[i],
						bizCtrlUserField);
				this.addRoleDataScope(sqlMapKey, roleCodes, ctrlTypeArray[i], ctrlPermi, bizCtrlDataFieldArray[i],
						bizCtrlUserField);
			}

		}
		return this;
	}

	/**
	 * user 数据范围
	 * 
	 * @param sqlMapKey
	 * @param user
	 * @param ctrlType
	 * @param ctrlPermi
	 * @param bizCtrlDataField
	 * @param bizCtrlUserField
	 */
	private void addUserDataScope(String sqlMapKey, User user, String ctrlType, String ctrlPermi,
			String bizCtrlDataField, String bizCtrlUserField) {
		// 获取用户数据范围配置
		int userDataScopeCount = 0; //这里需要重写
		if (userDataScopeCount == 0) {
			if (StringUtils.isNotBlank(bizCtrlUserField)) {
				this.addJoinWhere(sqlMapKey, bizCtrlUserField + " = '" + user.getUserCode() + "'");
				this.addFilter(sqlMapKey, bizCtrlUserField + " = '" + user.getUserCode() + "'");
				return;
			}
			this.addJoinWhere(sqlMapKey, "1=0");
			this.addFilter(sqlMapKey, "1=0");
			return;
		}
		String tmp = IdGen.randomBase62(4);
		this.addJoinFrom(sqlMapKey,
				" JOIN sys_user_data_scope " + tmp + " ON " + tmp + ".ctrl_data=" + bizCtrlDataField);
		this.addJoinWhere(sqlMapKey, tmp + ".ctrl_permi = '" + ctrlPermi + "' AND " + tmp + ".ctrl_type='" + ctrlType
				+ "' AND " + tmp + ".user_code='" + user.getUserCode() + "'");
		this.addFilter(sqlMapKey,
				" EXISTS (SELECT 1 FROM sys_user_data_scope WHERE ctrl_permi = '" + ctrlPermi + "' AND ctrl_type='"
						+ ctrlType + "' AND user_code='" + user.getUserCode() + "' AND ctrl_data=" + bizCtrlDataField
						+ ")");
	}

	/**
	 * role 数据范围
	 * 
	 * @param sqlMapKey
	 * @param roleList
	 * @param ctrlType
	 * @param ctrlPermi
	 * @param bizCtrlDataField
	 * @param bizCtrlUserField
	 */
	private void addRoleDataScope(String sqlMapKey, List<String> roleList, String ctrlType, String ctrlPermi,
			String bizCtrlDataField, String bizCtrlUserField) {
		if (roleList.size() > 0) {
			String tmp = IdGen.randomBase62(4);
			this.addJoinFrom(sqlMapKey,
					" JOIN sys_role_data_scope " + tmp + " ON " + tmp + ".ctrl_data = " + bizCtrlDataField);
			this.addJoinWhere(sqlMapKey, "OR (" + tmp + ".ctrl_permi='" + ctrlPermi + "' AND " + tmp + ".ctrl_type='"
					+ ctrlType + "' AND " + tmp + ".role_code IN ('" + StringUtils.join(roleList, "','") + "'))");
			this.addFilter(sqlMapKey,
					" EXISTS (SELECT 1 FROM sys_role_data_scope WHERE ctrl_permi = '" + ctrlPermi + "' AND ctrl_type='"
							+ ctrlType + "' AND role_code IN ('" + StringUtils.join(roleList, "','")
							+ "') AND ctrl_data=" + bizCtrlDataField + ")");
		}
	}

	/**
	 * role 數據范围
	 * 
	 * @param sqlMapKey
	 * @param user
	 * @param bizCtrlDataField
	 */
	private void addRoleDataScope(String sqlMapKey, User user, String bizCtrlDataField) {
		String tmp = IdGen.randomBase62(4);
		this.addJoinFrom(sqlMapKey, " JOIN sys_user_role " + tmp + " ON " + tmp + ".role_code = " + bizCtrlDataField);
		this.addJoinWhere(sqlMapKey, tmp + ".user_code = '" + user.getUserCode() + "'");
		this.addFilter(sqlMapKey, " EXISTS (SELECT 1 FROM sys_user_role WHERE user_code='" + user.getUserCode()
				+ "' AND role_code=" + bizCtrlDataField + ")");
	}

}
